<?php
/**
*/
class ActionRouter{
	//Members
	private	$_globalOutput;
	private $_uriRewriter;
	private $_params;
	
	//ActionRouter( )
	function __construct( ){
		//uses global conf
		global $_CONF;
		$this->_globalOutput = null;
		$this->_uriRewriter = new RewriteEngine( );			
		//Estrazione funzioni di protocollo
		$_params_str = '';
		$this->_params['functions'] = array( );
		while( ( $_token = $this->_uriRewriter->shift( ) ) != '' ){
			$_params_str .= '/'. $_token;
			$this->_params['functions'][] = $_token;
		}
		//Estrazione parametro lingua
		$this->_params['lang'] = str_replace( 
			array( $_params_str, $this->_uriRewriter->path->path, '/' ),
			array( '', '', '' ) ,
			$this->_uriRewriter->raw 
		);
		//Settaggio della base url
		$_CONF['paths']['base_url'] = $this->_uriRewriter->url;
		//Actions routing
		$this->_route( );
	}
	
	//_route( )
	private function _route( ){
		//Usa l'array globale di configurazione
		global $_CONF;
		//Usa gli array globali delle rewrite
		global $_RW_RULES;
		global $_RW_ERRORS;		
		global $_RW_DEFAULT;
		
		//Validazione del parametro lingua
		if( !isset( $_CONF['langs'][$this->_params['lang']] ) ){
			//echo 'lingua non supportata'
			$_base_lang_default_path = "{$this->_uriRewriter->path->path}/{$_CONF['DEFAULT_LANG']}/";
			if( $this->_uriRewriter->raw != $_base_lang_default_path ){
				header( 'HTTP/1.1 301 Moved Permanently' );
				header( 'Location: ' . $_base_lang_default_path );
				exit;
			}	
		}
		
		//Default path
		$_default_path = "{$this->_uriRewriter->path->path}/{$this->_params['lang']}/{$_RW_DEFAULT[$this->_params['lang']]}";
		//Error paths
		$_404_path = "{$this->_uriRewriter->path->path}/{$this->_params['lang']}/{$_RW_ERRORS['aliases'][$this->_params['lang']]['_404']}";
		$_500_path = "{$this->_uriRewriter->path->path}/{$this->_params['lang']}/{$_RW_ERRORS['aliases'][$this->_params['lang']]['_500']}";
				
		//Esamina tutti i tokens estratti dalla querystring
		$_functions = array( );
		foreach( $this->_params['functions'] as $key=>$value ){
			//Esamina l'ultimo elemento inserito nell'array delle funzioni
			//Se è un set di parametri
			if( $this->_isParametersSet( $value ) ){	
				//Se non esiste una funzione a cui associarli
				if( !count( $_functions ) ){
					//echo 'Non esiste una funzione che possa accogliere: ' . $value;
					if( $this->_uriRewriter->raw != $_500_path ){
						header( 'HTTP/1.1 500 Internal Server Error' );
						header( 'Location: ' . $_500_path );
					}
					exit;
				}
				//Se il valore precedente non ha un nome di funzione
				if( !isset( $_functions[ count( $_functions ) - 1 ]['name'] ) ){ 
					//echo 'Non esiste una funzione che possa accogliere: ' . $value;
					if( $this->_uriRewriter->raw != $_500_path ){
						header( 'HTTP/1.1 500 Internal Server Error' );
						header( 'Location: ' . $_500_path );
					}
					exit;
				}
				//Se il nome della funzione è al difuori della naming convention
				if( !$this->_isFunction( $_functions[ count( $_functions ) - 1 ]['name'] ) ){
					if( $this->_uriRewriter->raw != $_500_path ){
						header( 'HTTP/1.1 500 Internal Server Error' );
						header( 'Location: ' . $_500_path );
					}
					exit;
				}
				$_functions[ count( $_functions ) - 1 ]['params'] = $value;				
			}
			//Se è una funzione
			else{ 
				$_functions[ ] = array( 'name' => $value, 'params' => null );	
			}
		}
		//Non è stato istanziato uno stack di chiamate
		if ( !is_array( $_functions ) ){
			if( $this->_uriRewriter->raw != $_500_path ){
				header( 'HTTP/1.1 500 Internal Server Error' );
				header( 'Location: ' . $_500_path );
				exit;
			}
		}
		//Se la chiamata è quella di base
		if( !count( $_functions ) ){
			//Va alla pagina di default come da opzioni
			if( $this->_uriRewriter->raw != $_default_path ){
				header( 'HTTP/1.1 301 Moved Permanently' );
				header( 'Location: ' . $_default_path );
				exit;
			}
		}
		//Setta la lingua in sessione
		$_SESSION['lang'] = $this->_params['lang'];
		//Include le unità necessarie all'esecuzione delle funzioni richieste
		//Parametri propagati dalla funzione precedente
		$_pparams = null;
		foreach( $_functions as $key=>$value ){		
			if( !isset( $_RW_RULES['functions'][$this->_params['lang']][$value['name']] ) ){
				//echo "Non esiste alias nella lingua {$this->_params['lang']} per {$value['name']}";
				if( $this->_uriRewriter->raw != $_404_path ){
					header( 'HTTP/1.1 404 Not Found' );
					header( 'Location: ' . $_404_path );
					exit;
				}
			}
			//Include il file con la funzione di protocollo da eseguire
			$_langued_alias = $_RW_RULES['functions'][$this->_params['lang']][$value['name']];
			$_action_file_name = $_CONF['paths']['actions'] . $_CONF['const']['ACTION_PREFIX'] . $_langued_alias . $_CONF['const']['ACTION_SUFFIX'];
			require_once( $_action_file_name );
			$_func_name = 'ProtocolFunction_' . $_langued_alias;
			if( !in_array( $_func_name, get_declared_classes( ) ) ){
				//echo "Non esiste action per {$_func_name}";
				if( $this->_uriRewriter->raw != $_404_path ){
					header( 'HTTP/1.1 404 Not Found' );
					header( 'Location: ' . $_404_path );
					exit;
				}
			}
			//Inizializzazione funzione di protocollo
			$_func = new $_func_name( $value['params'], $_pparams );
			$_pparams = null;
			//Se la funzione chiamata non ha parametri da propagare
			if( !$_func->propagate( ) ){
				//Le richieste successive vengono ignorate e la concatenazione dei risultati viene interrotta
				$_clean_path = "{$this->_uriRewriter->path->path}/{$this->_params['lang']}/{$value['name']}/{$value['params']}";
				//Evita la ricorsione
				if( $this->_uriRewriter->raw != $_clean_path ){
					header( 'HTTP/1.1 301 Moved Permanently' );
					header( 'Location: ' . $_clean_path );
					exit;
				}
			}
			//Altrimenti esegue la funzione e propaga eventuali parametri restituiti
			$_pparams = $_func->exec( );
			//Se si verifica un errore runtime dell'action
			if( $_pparams === false ){
				if( $this->_uriRewriter->raw != $_500_path ){
					header( 'HTTP/1.1 500 Internal Server Error' );
					header( 'Location: ' . $_500_path );
					exit;
				}
			}
		}
		return true;
	}
	
	//getLanguedPath( $path )
	//returns the langued version ( in the current selected language ) of a given canonical path
	public static function getLanguedPath( $path ){
		//Logger
		$_logger = new Logger( );
		global $_RW_RULES;
		global $_RW_ERRORS;
		global $_CONF;
		$_REWRITER = new RewriteEngine( );
		$_500_path = "{$_REWRITER->path->path}/{$_SESSION['lang']}/{$_RW_ERRORS['aliases'][$_SESSION['lang']]['_500']}";
		$_res = "{$_SESSION['lang']}";
		$_tokens = explode( "/", $path );
		foreach( $_tokens as $key=>$value ){
			if( ActionRouter::_isFunction( $value ) ){
				$_found = false;
				foreach( $_RW_RULES['functions'][$_SESSION['lang']] as $idx=>$rule ){
					if( $rule == $value ){
						$_res .= "/{$idx}";
						$_found = true;
					}
				}
				if( !$_found ){
					//Error logging
					$_logger->log( $_CONF['log_levels']['FATAL_ERROR'] , "Error while connecting calculating action '{$value}' [{$_SESSION['lang']}] langued name", 0, '' );
					//Redirect to 500 error
					if( $_REWRITER->raw != $_500_path ){
						header( 'HTTP/1.1 500 Internal Server Error' );
						header( 'Location: ' . $_500_path );
						exit;
					}
				}
			}
			else if( ActionRouter::_isParametersSet( $value ) ){
				$res .= "/{$value}";
			}
			else{
				//Error logging
				$_logger->log( $_CONF['log_levels']['FATAL_ERROR'] , "Malformed segment name during path translation: {$value}", 0, '' );
				//Redirect to 500 error
				if( $_REWRITER->raw != $_500_path ){
					header( 'HTTP/1.1 500 Internal Server Error' );
					header( 'Location: ' . $_500_path );
					exit;
				}
			}
		}
		return $_CONF['paths']['base_url'] . $_res;
	}
	
	//_isFunction( )
	private static function _isFunction( $token ){
		return ( !preg_match( '/\-(.*)/', $token ) );
	}
	//_isParametersSet( )
	private static function _isParametersSet( $token ){
		return ( preg_match( '/\-(.*)/', $token ) );
	}
}
?>